package com.stm.bi.executor;

import com.stm.bi.dto.cmd.*;
import com.stm.bi.dto.query.ReportDimensionListQry;
import com.stm.bi.dto.query.ReportModelListQry;
import com.stm.bi.dto.query.ReportStandardListQry;
import com.stm.bi.dto.query.ReportSubjectListQry;
import com.stm.bi.dto.vo.ReportDimensionVO;
import com.stm.bi.dto.vo.ReportModelVO;
import com.stm.bi.dto.vo.ReportStandardVO;
import com.stm.bi.dto.vo.ReportSubjectVO;
import com.stm.bi.jdbc.DataSourceEnum;
import com.stm.bi.jdbc.DataSourceSwitch;
import com.stm.bi.repository.report.ReportDimensionRepository;
import com.stm.bi.repository.report.ReportModelRepository;
import com.stm.bi.repository.report.ReportStandardRepository;
import com.stm.bi.repository.report.ReportSubjectRepository;
import com.stm.framework.core.util.StringUtil;
import com.stm.framework.dto.Response;
import com.stm.framework.snowflake.Snowflake;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 报表模型-保存执行器
 *
 * @author zhouyuanpeng
 * @date 2025-05-22
 */
@Component
public class ReportModelSaveExe {
    @Resource
    private ReportModelRepository reportModelRepository;
    @Resource
    private Snowflake snowflake;
    @Resource
    private ReportDimensionRepository reportDimensionRepository;
    @Resource
    private ReportStandardRepository reportStandardRepository;
    @Resource
    private ReportSubjectRepository reportSubjectRepository;

    /**
     * 保存
     *
     * @param reportModelAdd
     */
    @DataSourceSwitch(DataSourceEnum.REPORT)
    @Transactional(rollbackFor = Exception.class)
    public Response<ReportModelAdd> createOrUpdate(ReportModelAdd reportModelAdd) {

        // 判断
        if (StringUtil.isEmpty(reportModelAdd.getDimensions())) {
            return Response.failure("请配置维度池");
        }
        if (Integer.parseInt(reportModelAdd.getDimensionNum()) != reportModelAdd.getDimensions().size()) {
            return Response.failure("维度数量不匹配");
        }
        if (StringUtil.isEmpty(reportModelAdd.getStandards())) {
            return Response.failure("请配置水准");
        }

        boolean isAdd = false;
        if (reportModelAdd.getId() == null) {
            // 创建
            reportModelAdd.setId(snowflake.nextId());
            isAdd = true;
        }

        ReportModelVO reportModelByName = reportModelRepository.selectByName(reportModelAdd.getName());
        if (reportModelByName != null && !reportModelAdd.getId().equals(reportModelByName.getId())) {
                return Response.failure("报表名称已存在");
        }

        // 历史数据清理
        List<Long> dimensionIds = new ArrayList<>();
        List<Long> standardIds = new ArrayList<>();
        List<Long> subjectIds = new ArrayList<>();
        Map<Long, List<Long>> standardSubjectMap = new HashMap<>();
        if (!isAdd) {
            List<ReportDimensionVO> reportDimensionList = reportDimensionRepository.selectList(new ReportDimensionListQry().setModelId(reportModelAdd.getId()));
            dimensionIds.addAll(reportDimensionList.stream().map(ReportDimensionVO::getId).toList());
            List<ReportStandardVO> reportStandardList = reportStandardRepository.selectList(new ReportStandardListQry().setModelId(reportModelAdd.getId()));
            standardIds.addAll(reportStandardList.stream().map(ReportStandardVO::getId).toList());
            List<ReportSubjectVO> reportSubjectList = reportSubjectRepository.selectList(new ReportSubjectListQry().setModelId(reportModelAdd.getId()));
            subjectIds.addAll(reportSubjectList.stream().map(ReportSubjectVO::getId).toList());
            standardSubjectMap = reportSubjectList.stream().collect(Collectors.groupingBy(ReportSubjectVO::getStandardId, Collectors.mapping(ReportSubjectVO::getId, Collectors.toList())));
        }


        // 保存维度池
        int idx = 1;

        List<ReportDimensionAdd> dimensionAddList = new ArrayList<>();
        List<ReportDimensionAdd> dimensionUpdList = new ArrayList<>();
        Set<String> dimesionTypeSet = new HashSet<>();
        for (ReportDimensionAdd reportDimensionAdd : reportModelAdd.getDimensions()) {

            if (dimesionTypeSet.contains(reportDimensionAdd.getType())) {
                return Response.failure("报表维度不能相同");
            }  else {
                dimesionTypeSet.add(reportDimensionAdd.getType());
            }

            reportDimensionAdd.setModelId(reportModelAdd.getId())
                    .setIdx(idx++);
            if (reportDimensionAdd.getId() == null) {
                reportDimensionAdd.setId(snowflake.nextId());
                dimensionAddList.add(reportDimensionAdd);
            } else {
                dimensionUpdList.add(reportDimensionAdd);
            }
            dimensionIds.remove(reportDimensionAdd.getId());
        }

        // 保存水准
        List<ReportStandardAdd> standardAddList = new ArrayList<>();
        List<ReportStandardAdd> standardUpdList = new ArrayList<>();
        List<ReportSubjectAdd> subjectAddList = new ArrayList<>();
        List<ReportSubjectAdd> subjectUpdList = new ArrayList<>();
        idx = 1;
        for (ReportStandardAdd reportStandardAdd : reportModelAdd.getStandards()) {
            reportStandardAdd.setModelId(reportModelAdd.getId())
                    .setIdx(idx++)
                    .setStatus(0);
            if (reportStandardAdd.getId() == null) {
                reportStandardAdd.setId(snowflake.nextId());
                standardAddList.add(reportStandardAdd);
            } else {
                standardUpdList.add(reportStandardAdd);
            }
            standardIds.remove(reportStandardAdd.getId());

            // 保存科目
            int subIdx = 1;
            for (ReportSubjectAdd reportSubjectAdd : reportStandardAdd.getSubjects()) {
                reportSubjectAdd.setModelId(reportModelAdd.getId())
                        .setStandardId(reportStandardAdd.getId())
                        .setIdx(subIdx++);

                if (reportSubjectAdd.getId() == null) {
                    reportSubjectAdd.setId(snowflake.nextId());
                    subjectAddList.add(reportSubjectAdd);
                } else {
                    subjectUpdList.add(reportSubjectAdd);
                }
                subjectIds.remove(reportSubjectAdd.getId());
            }
        }
        // 水准数
        reportModelAdd.setStandardNum(idx - 1)
                .setStatus(0);

        // 统一保存
        boolean res;
        if (isAdd) {
            res = reportModelRepository.create(reportModelAdd);
        } else {
            res = reportModelRepository.update(reportModelAdd);
        }
        if (!dimensionAddList.isEmpty()) {
            res = res && reportDimensionRepository.batchCreate(dimensionAddList);
        }
        if (!dimensionUpdList.isEmpty()) {
            res = res && reportDimensionRepository.batchUpdate(dimensionUpdList);
        }
        if (!standardAddList.isEmpty()) {
            res = res && reportStandardRepository.batchCreate(standardAddList);
        }
        if (!standardUpdList.isEmpty()) {
            res = res && reportStandardRepository.batchUpdate(standardUpdList);
        }
        if (!subjectAddList.isEmpty()) {
            res = res && reportSubjectRepository.batchCreate(subjectAddList);
        }
        if (!subjectUpdList.isEmpty()) {
            res = res && reportSubjectRepository.batchUpdate(subjectUpdList);
        }
        // 清理多余
        if (!dimensionIds.isEmpty()) {
            res = res && reportDimensionRepository.logicDeleteByIds(dimensionIds);
        }
        if (!standardIds.isEmpty()) {
            res = res && reportStandardRepository.logicDeleteByIds(standardIds);
            for (Long standardId : standardIds) {
                if (standardSubjectMap.containsKey(standardId)) {
                    subjectIds.addAll(standardSubjectMap.get(standardId));
                }
            }
        }
        if (!subjectIds.isEmpty()) {
            res = res && reportSubjectRepository.logicDeleteByIds(subjectIds);
        }

        if (!res) {
            throw new RuntimeException("自定义报表保存失败");
        }

        return Response.of(reportModelAdd);
    }

}
